#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <execinfo.h>
#include "SignalHadler.h"
#define ngx_signal_helper(n)     SIG##n
#define ngx_signal_value(n)      ngx_signal_helper(n)
#define ngx_value_helper(n)   #n
#define ngx_value(n)          ngx_value_helper(n)
#define NGX_SHUTDOWN_SIGNAL      QUIT
#define NGX_TERMINATE_SIGNAL     TERM
#define NGX_NOACCEPT_SIGNAL      WINCH
#define NGX_RECONFIGURE_SIGNAL   HUP
#define NGX_REOPEN_SIGNAL        USR1
#define NGX_CHANGEBIN_SIGNAL     USR2
#define ngx_errno                errno
#define NGX_OK					0
#define NGX_ERROR				-1
typedef intptr_t ngx_int_t;
typedef int ngx_err_t;
CTCPServerPtr _srv;
void out_stack(char *sig);
static void
ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext);
typedef struct {
	int     signo;
	char   *signame;
	char   *name;
	void(*handler)(int signo, siginfo_t *siginfo, void *ucontext);
} ngx_signal_t;
ngx_signal_t  signals[] = {
	{ ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
	"SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
	"reload",
	ngx_signal_handler },

	{ ngx_signal_value(NGX_REOPEN_SIGNAL),
	"SIG" ngx_value(NGX_REOPEN_SIGNAL),
	"reopen",
	ngx_signal_handler },

	{ ngx_signal_value(NGX_NOACCEPT_SIGNAL),
	"SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
	"",
	ngx_signal_handler },

	{ ngx_signal_value(NGX_TERMINATE_SIGNAL),
	"SIG" ngx_value(NGX_TERMINATE_SIGNAL),
	"stop",
	ngx_signal_handler },

	{ ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
	"SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
	"quit",
	ngx_signal_handler },

	{ ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
	"SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
	"",
	ngx_signal_handler },

	{ SIGALRM, "SIGALRM", "", ngx_signal_handler },

	{ SIGINT, "SIGINT", "", ngx_signal_handler },

	{ SIGIO, "SIGIO", "", ngx_signal_handler },

	{ SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
	{ SIGSEGV, "SIGSEGV", "", ngx_signal_handler },
	
	{ SIGSYS, "SIGSYS, SIG_IGN", "", NULL },

	{ SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },

	{ 0, NULL, "", NULL }
};

static void signal_exit(int dunno)
{
	char* signal_str = "";
	char dunno_str[10] = { 0 };
	sprintf(dunno_str, "%d", dunno);
	switch (dunno)
	{
	case 1:
		signal_str = "SIGHUP(1)";
		break;
	case 2:
		signal_str = "SIGINT(2:CTRL_C)"; //CTRL_C
		_srv->StopServer();
		break;
	case 3:
		signal_str = "SIGQUIT(3)";
		break;
	case 6:
	{
		signal_str = "SIGABRT(6)";
		out_stack(signal_str);
	}
	break;
	case 9:
		signal_str = "SIGKILL(9)";
		break;
	case 15:
		signal_str = "SIGTERM(15 KILL)"; //kill 
		break;
	case 11:
	{
		signal_str = "SIGSEGV(11)"; //SIGSEGV 
		out_stack(signal_str);
	}
	break;
	default:
		signal_str = "OTHER";
		break;
	}		
	exit(0);
}

static void output_addrline(char addr[])
{
	char cmd[256];
	char line[256];
	char addrline[32] = { 0, };
	char *str1, *str2;
	FILE* file;

	str1 = strchr(addr, '[');
	str2 = strchr(addr, ']');
	if (str1 == NULL || str2 == NULL)
	{
		return;
	}
	memcpy(addrline, str1 + 1, str2 - str1);
	snprintf(cmd, sizeof(cmd), "addr2line -e /proc/%d/exe %s ", getpid(), addrline);
	file = popen(cmd, "r");
	if (NULL != fgets(line, 256, file))
	{
		printf("%s\n", line);
	}
	pclose(file);
}
void out_stack(char *sig)
{
	char buf[1024];
	char cmd[1024];
	FILE *fh;

	snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
	if (!(fh = fopen(buf, "r")))
		exit(0);
	if (!fgets(buf, sizeof(buf), fh))
		exit(0);
	fclose(fh);
	if (buf[strlen(buf) - 1] == '/n')
		buf[strlen(buf) - 1] = '/0';
	snprintf(cmd, sizeof(cmd), "gdb %s %d -ex=bt > ./a.txt", buf, getpid());
	system(cmd);
}



int ngx_init_signals(CTCPServerPtr srv)
{
	ngx_signal_t      *sig;
	struct sigaction   sa;
	_srv = srv;
#if 0
	for (sig = signals; sig->signo != 0; sig++) {
		memset(&sa, 0, sizeof(struct sigaction));

		if (sig->handler) {
			sa.sa_sigaction = sig->handler;
			sa.sa_flags = SA_SIGINFO;

		}
		else {
			sa.sa_handler = SIG_IGN;
		}

		sigemptyset(&sa.sa_mask);
		if (sigaction(sig->signo, &sa, NULL) == -1) {
			return NGX_ERROR;
		}
	}	
#endif	
	signal(SIGHUP, signal_exit);
	signal(SIGINT, signal_exit);
	signal(SIGQUIT, signal_exit);
	signal(SIGABRT, signal_exit);
	signal(SIGKILL, signal_exit);
	signal(SIGTERM, signal_exit);
	signal(SIGSEGV, signal_exit);
	return NGX_OK;
}
static void
ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
{
	char            *action;
	ngx_int_t        ignore;
	ngx_err_t        err;
	ngx_signal_t    *sig;

	ignore = 0;

	err = ngx_errno;

	for (sig = signals; sig->signo != 0; sig++) {
		if (sig->signo == signo) {
			break;
		}
	}


	action = "";

	switch (signo) {

	case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):		
		exit(0);
		break;

	case ngx_signal_value(NGX_TERMINATE_SIGNAL):
	case SIGINT:
	case SIGSEGV:
	{
		char buf[1024];
		char cmd[1024];
		FILE *fh;

		snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
		if (!(fh = fopen(buf, "r")))
			exit(0);
		if (!fgets(buf, sizeof(buf), fh))
			exit(0);
		fclose(fh);
		if (buf[strlen(buf) - 1] == '/n')
			buf[strlen(buf) - 1] = '/0';
		snprintf(cmd, sizeof(cmd), "gdb %s %d -ex=bt > ./a.txt", buf, getpid());
		system(cmd);

		exit(0);

	}		
		break;

	case ngx_signal_value(NGX_NOACCEPT_SIGNAL):	
		break;

	case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):			
		break;

	case ngx_signal_value(NGX_REOPEN_SIGNAL):
		break;

	case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
		break;

	case SIGALRM:
		break;

	case SIGIO:
		break;

	case SIGCHLD:
		break;
	}		
}



